package com.carpark.ejb.DAO;

import com.carpark.ejb.Model.ParkingspacesModel;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

/**
 *
 * @author Sawior
 */
@Stateful
public class ParkingspacesDAOImpl implements ParkingspacesDAO {

    private EntityManager entityManager;

    public ParkingspacesDAOImpl() {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("persistenceUnit");
        entityManager = factory.createEntityManager();
    }

    @Override
    public List<ParkingspacesModel> getAllParkingSpaces() {
        return (List<ParkingspacesModel>) entityManager.createNamedQuery("ParkingspacesModel.findAll").getResultList();
    }

    @Override
    public int getParkingSpacesSize() {
        return entityManager.createNamedQuery("ParkingspacesModel.findAll").getResultList().size();
    }

    @Override
    public ParkingspacesModel getParkingSpacesByNumber(Integer number) {
        return (ParkingspacesModel) entityManager.createNamedQuery("ParkingspacesModel.findByNumber").setParameter("number", number).getSingleResult();
    }

    @Override
    public List<ParkingspacesModel> getParkingSpacesByType(String type) {
        return (List<ParkingspacesModel>) entityManager.createNamedQuery("ParkingspacesModel.findByType").setParameter("type", type).getResultList();
    }

    @Override
    public List<ParkingspacesModel> getParkingSpacesByStatus(String status) {
        return (List<ParkingspacesModel>) entityManager.createNamedQuery("ParkingspacesModel.findByStatus").setParameter("status", status).getResultList();
    }

    void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    public void addSpace(ParkingspacesModel space) {
        entityManager.getTransaction().begin();
        entityManager.persist(space);
        entityManager.flush();
        entityManager.refresh(space);
        entityManager.persist(space);
        entityManager.getTransaction().commit();
    }

    @Override
    public void updateSpace(ParkingspacesModel space) {
        entityManager.getTransaction().begin();
        ParkingspacesModel actual = getParkingSpacesByNumber(space.getNumber());
        entityManager.persist(actual);
        actual.setStatus(space.getStatus());
        actual.setNumber(space.getNumber());

        entityManager.getTransaction().commit();
    }

    @Override
    public void removeSpace(ParkingspacesModel space) {
        ParkingspacesModel rowToDelete = getParkingSpacesByNumber(space.getNumber());
        entityManager.getTransaction().begin();
        entityManager.remove(rowToDelete);
        entityManager.getTransaction().commit();
    }

    @Override
    public List<ParkingspacesModel> getParkingSpacesForReservation(Date issue, Date end, String carType) {
        List<ParkingspacesModel> timeFiltered = (List<ParkingspacesModel>) entityManager.createNamedQuery("ParkingspacesModel.findByTimeAnType").setParameter("dateIs", issue).setParameter("passType", "Permanent").setParameter("dateExp", end).getResultList();
        List<ParkingspacesModel> typeFiltered = (List<ParkingspacesModel>) entityManager.createNamedQuery("ParkingspacesModel.findByType").setParameter("type", carType).getResultList();

        List<ParkingspacesModel> all = (List<ParkingspacesModel>) entityManager.createNamedQuery("ParkingspacesModel.findByType").setParameter("type", "All").getResultList();
        List<ParkingspacesModel> special = (List<ParkingspacesModel>) entityManager.createNamedQuery("ParkingspacesModel.findByType").setParameter("type", "Special").getResultList();
        typeFiltered.addAll(all);
        typeFiltered.addAll(special);
        List<ParkingspacesModel> result = new ArrayList<ParkingspacesModel>();
        for (ParkingspacesModel space : typeFiltered) {
            if (!timeFiltered.contains(space)) {
                result.add(space);
            }

        }
        return result;
    }

    @Override
    public boolean synchronizeParkingSpacesWithConfiguration(List<ParkingspacesModel> spacesToUpdate) {
        entityManager.getTransaction().begin();
        List<ParkingspacesModel> allSpaces = this.getAllParkingSpaces();

        try {
            for (ParkingspacesModel space : allSpaces) {
                if (spacesToUpdate.contains(space)) {
                    ParkingspacesModel newData = spacesToUpdate.get(spacesToUpdate.indexOf(space));
                    ParkingspacesModel after = entityManager.merge(space);
                    after.setStatus(newData.getStatus());
                    after.setType(newData.getType());
                } else {
                    entityManager.remove(space);
                }
            }
            for (ParkingspacesModel spaceToUp : spacesToUpdate) {
                if (!allSpaces.contains(spaceToUp)) {
                    entityManager.persist(spaceToUp);
                    entityManager.flush();
                    entityManager.refresh(spaceToUp);
                }
            }
            entityManager.getTransaction().commit();
        } catch (Throwable ex) {
            Logger.getLogger(ParkingspacesDAOImpl.class.getName()).log(Level.SEVERE, "[CarPark] Error during saving new parking spaces.", ex);
            return false;
        }
        return true;
    }
}
